#include "Thread.h"
#include <thread>

#include "Runtime/Log/Logger.h"

namespace Alice{
	int32 GRenderThreadPollPeriodMs = -1;
	std::atomic<ENamedThreads> RenderThreadStatics::RenderThread;
	std::atomic<ENamedThreads> RenderThreadStatics::RenderThread_Local;
	uint32 Thread::RunnableTlsSlot = Thread::GetTlsSlot();
	uint32 Thread::RenderThreadID=0;
	uint32 Thread::GameThreadID=0;
	Thread::Thread(const char *name)
	{
		memset(mThreadName,0,64);
		strcpy(mThreadName,name);
		mThreadInitSyncEvent=nullptr;
	}
	Thread::~Thread()
	{
		Kill(true);
	}

	void Thread::SetTls()
	{
		PlatformTLS::SetTlsValue( RunnableTlsSlot, this );
	}
	void Thread::FreeTls()
	{
		PlatformTLS::SetTlsValue( RunnableTlsSlot, nullptr );
	}
	bool Thread::Kill(bool bShouldWait)
	{
		bool bDidExitOK = true;
		if (mThreadContext)
		{
			mThreadContext->Stop();
		}
		if (bShouldWait == true)
		{
			if(mThread->joinable())
			{
				mThread->join();
			}
		}
		mThread = NULL;
		return bDidExitOK;
	}
	void Thread::WaitForCompletion()
	{
		mThread->join();
	}
	
	uint32 Thread::GetTlsSlot()
	{
		uint32 TlsSlot = PlatformTLS::AllocTlsSlot();
		return TlsSlot;
	}

	Thread* Thread::Create(const char * name,ThreadContext* threadContext)
	{
		Thread*thread=new Thread(name);
		thread->CreateInternal(threadContext);
		thread->PostCreate();
		return thread;
	}
	bool Thread::CreateInternal(ThreadContext* threadContext)
	{
		mThreadContext = threadContext;
		mThreadInitSyncEvent	= new Event;
		//Debug("new mThreadInitSyncEvent [%p]",mThreadInitSyncEvent);
		mThread = new std::thread(&Thread::Entry,this);
		if (mThread == nullptr)
		{
			mThreadContext = nullptr;
		}
		else
		{
			mThreadInitSyncEvent->Wait(INFINITE);
		}
		//Debug("delete mThreadInitSyncEvent [%p]",mThreadInitSyncEvent);
		delete mThreadInitSyncEvent;
		return true;
	}
	void Thread::Entry()
	{
		mThreadID=mThread->get_id();
		PlatformMisc::SetThreadName(mThreadName);
		// Initialize the runnable object
		if (mThreadContext->Init() == true)
		{
			// Initialization has completed, release the sync event
			mThreadInitSyncEvent->TriggerAll();

			// Setup TLS for this thread, used by FTlsAutoCleanup objects.
			SetTls();

			// Now run the task that needs to be done
			mThreadContext->Run();
			// Allow any allocated resources to be cleaned up
			mThreadContext->Exit();
			FreeTls();
		}
		else
		{
			// Initialization has failed, release the sync event
			mThreadInitSyncEvent->TriggerAll();
		}
	}

}
